{
  "name": "Case 67 - Hotel Guest Experience Monitor (Sheraton Hotels)",
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "weeks",
              "triggerAtDay": [
                1
              ],
              "triggerAtHour": 9
            }
          ]
        }
      },
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        -784,
        -80
      ],
      "id": "00e951bb-f010-4f10-96c9-889b497b1ace",
      "name": "Weekly Schedule - Monday 9 AM"
    },
    {
      "parameters": {
        "actorId": {
          "__rl": true,
          "value": "Xb8osYTtOjlsgI6k9",
          "mode": "id",
          "cachedResultName": "Google Maps Scraper"
        },
        "customBody": "{\n  \"language\": \"en\",\n  \"maxReviews\": 100,\n  \"personalData\": true,\n  \"startUrls\": [\n    {\n      \"url\": \"https://www.google.com/maps/place/Sheraton+New+York+Times+Square+Hotel/@40.7625851,-73.9837139,17z/data=!3m1!5s0x89c258f85fb4cddf:0xb89b90a954e9ebd4!4m9!3m8!1s0x89c258f88254f2c3:0xc307e150c50c51f7!5m2!4m1!1i2!8m2!3d40.7625811!4d-73.981139!16s%2Fm%2F065y05x\"\n    }\n  ],\n  \"reviewsSort\": \"newest\",\n  \"reviewsOrigin\": \"all\"\n}"
      },
      "type": "@apify/n8n-nodes-apify.apify",
      "typeVersion": 1,
      "position": [
        -592,
        -80
      ],
      "id": "45e4fe88-b075-4ff4-a6c8-0fe356df804c",
      "name": "Scrape Hotel Reviews",
      "credentials": {
        "apifyApi": {
          "id": "w5S6YBbbyUddEfQA",
          "name": "Apify account"
        }
      }
    },
    {
      "parameters": {
        "resource": "Datasets",
        "datasetId": "={{ $json.defaultDatasetId }}",
        "limit": 100
      },
      "type": "@apify/n8n-nodes-apify.apify",
      "typeVersion": 1,
      "position": [
        -400,
        -80
      ],
      "id": "f645678e-3b76-46b8-b52f-083989914abb",
      "name": "Get Dataset Items",
      "credentials": {
        "apifyApi": {
          "id": "w5S6YBbbyUddEfQA",
          "name": "Apify account"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 1
          },
          "conditions": [
            {
              "id": "filter-1star",
              "leftValue": "={{ $json.stars }}",
              "rightValue": 1,
              "operator": {
                "type": "number",
                "operation": "equals"
              }
            },
            {
              "id": "filter-2star",
              "leftValue": "={{ $json.stars }}",
              "rightValue": 2,
              "operator": {
                "type": "number",
                "operation": "equals"
              }
            }
          ],
          "combinator": "or"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.filter",
      "typeVersion": 2,
      "position": [
        -208,
        -80
      ],
      "id": "969392ba-1b21-414e-810e-3a9654d0aa51",
      "name": "Filter 1-2 Star Reviews"
    },
    {
      "parameters": {
        "modelId": {
          "__rl": true,
          "value": "gpt-4o",
          "mode": "list",
          "cachedResultName": "GPT-4o"
        },
        "responses": {
          "values": [
            {
              "role": "system",
              "content": "You are a Hotel Operations Analyst. Read the review carefully and categorize it.\n\nReturn ONLY this JSON format:\n{\n  \"complaint_category\": \"Room Cleanliness|Front Desk Service|Maintenance Issues|Noise Levels|Amenities|Value for Money|Other\",\n  \"severity\": \"critical|high|medium|low\",\n  \"emotional_tone\": \"Angry|Frustrated|Disappointed|Calm|Sarcastic\",\n  \"specific_issue\": \"what went wrong\",\n  \"key_quote\": \"most important sentence from review\"\n}\n\nHOW TO CATEGORIZE:\n\nRoom Cleanliness = Dirty rooms, bathrooms, linens, housekeeping issues\nKeywords: dirty, filthy, stained, unclean, bugs, hair, mold\nExample: \"Room was dirty with hair in bathroom\" → Room Cleanliness\n\nFront Desk Service = Check-in problems, staff attitude, customer service\nKeywords: rude staff, slow check-in, unhelpful, attitude problem\nExample: \"Front desk was incredibly rude\" → Front Desk Service\n\nMaintenance Issues = Broken AC, plumbing, TV, WiFi, appliances\nKeywords: broken, not working, no hot water, AC failed, WiFi down\nExample: \"Air conditioning didn't work all night\" → Maintenance Issues\n\nNoise Levels = Loud neighbors, street noise, thin walls\nKeywords: loud, noisy, couldn't sleep, parties, construction\nExample: \"Couldn't sleep due to noise\" → Noise Levels\n\nAmenities = Pool, gym, parking, breakfast issues\nKeywords: pool closed, no parking, breakfast terrible, gym dirty\nExample: \"Pool was closed without notice\" → Amenities\n\nValue for Money = Overpriced, hidden fees, not worth it\nKeywords: overpriced, expensive, hidden charges, rip-off\nExample: \"Way too expensive for what you get\" → Value for Money\n\nOther = Everything else\nExample: \"Location was far from attractions\" → Other\n\nSEVERITY RULES:\n- critical: Health/safety (bedbugs, mold, no heat/AC in extreme weather)\n- high: Major failures, very angry guest, multiple issues\n- medium: Frustrating experience, disappointed guest\n- low: Minor inconveniences, constructive feedback\n\nEMOTIONAL TONE RULES:\n- Angry: Profanity, threats, extreme anger, \"never coming back\"\n- Frustrated: Multiple complaints, \"disappointed\", \"ridiculous\"\n- Disappointed: Unmet expectations, sad tone\n- Calm: Neutral feedback, no emotion\n- Sarcastic: Mockery, ironic comments\n\nReturn ONLY the JSON. No explanation."
            },
            {
              "content": "=Analyze this hotel review:\n\nHotel: {{ $json.title }}\nGuest: {{ $json.name }}\nRating: {{ $json.stars }} stars\nDate: {{ $json.publishedAtDate }}\nReview Text: {{ $json.text }}\n\nReturn only JSON."
            }
          ]
        },
        "builtInTools": {},
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "typeVersion": 2.1,
      "position": [
        -16,
        -80
      ],
      "id": "b6401001-dcba-4963-b2a2-f9050389e166",
      "name": "AI: Analyze Review",
      "credentials": {
        "openAiApi": {
          "id": "ICwxUBbatsF2sDvy",
          "name": "OpenAi account"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// STANDARD AI RESPONSE PARSER\n// Use this after every AI node to convert text into drag-droppable fields\n// Students: You don't need to understand this code - just connect it after AI nodes!\n\nconst items = [];\nconst input = $input.all();\n\ninput.forEach((item, index) => {\n  try {\n    // Get AI response text\n    const aiText = item.json.output[0].content[0].text;\n    \n    // Clean markdown code blocks if present\n    const cleaned = aiText.replace(/```json\\n?/g, '').replace(/```\\n?/g, '').trim();\n    \n    // Parse JSON string into object\n    const parsed = JSON.parse(cleaned);\n    \n    // Return parsed fields (now you can drag-drop these!)\n    items.push({\n      json: parsed\n    });\n  } catch (error) {\n    console.error(`Error parsing AI response for item ${index}:`, error.message);\n    // Return empty fields if parsing fails\n    items.push({\n      json: {\n        error: `Parse failed: ${error.message}`\n      }\n    });\n  }\n});\n\nreturn items;\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        256,
        -80
      ],
      "id": "b362213e-9691-4e1b-bf71-57713c84d0ef",
      "name": "Parse AI Response"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "cat",
              "name": "complaint_category",
              "value": "={{ $json.complaint_category }}",
              "type": "string"
            },
            {
              "id": "sev",
              "name": "severity",
              "value": "={{ $json.severity }}",
              "type": "string"
            },
            {
              "id": "tone",
              "name": "emotional_tone",
              "value": "={{ $json.emotional_tone }}",
              "type": "string"
            },
            {
              "id": "issue",
              "name": "specific_issue",
              "value": "={{ $json.specific_issue }}",
              "type": "string"
            },
            {
              "id": "quote",
              "name": "key_quote",
              "value": "={{ $json.key_quote }}",
              "type": "string"
            },
            {
              "id": "date",
              "name": "review_date",
              "value": "={{ $('Filter 1-2 Star Reviews').item.json.publishedAtDate }}",
              "type": "string"
            },
            {
              "id": "reviewer",
              "name": "guest_name",
              "value": "={{ $('Filter 1-2 Star Reviews').item.json.name }}",
              "type": "string"
            },
            {
              "id": "rating",
              "name": "star_rating",
              "value": "={{ $('Filter 1-2 Star Reviews').item.json.stars }}",
              "type": "number"
            },
            {
              "id": "text",
              "name": "review_text",
              "value": "={{ $('Filter 1-2 Star Reviews').item.json.textTranslated || $('Filter 1-2 Star Reviews').item.json.text }}",
              "type": "string"
            },
            {
              "id": "url",
              "name": "review_url",
              "value": "={{ $('Filter 1-2 Star Reviews').item.json.reviewUrl }}",
              "type": "string"
            },
            {
              "id": "loc",
              "name": "hotel_name",
              "value": "={{ $('Filter 1-2 Star Reviews').item.json.title }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        400,
        -80
      ],
      "id": "88795c3c-7714-4b33-8eb1-a7741f610914",
      "name": "Edit Fields"
    },
    {
      "parameters": {
        "operation": "append",
        "documentId": {
          "__rl": true,
          "value": "1wMoRy4eHfBcIm_v3lQQ-H9oNTvAxP-fKRHomVerwkbc",
          "mode": "list",
          "cachedResultName": "Case 67 - Hotel Guest experience Log",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1wMoRy4eHfBcIm_v3lQQ-H9oNTvAxP-fKRHomVerwkbc/edit?usp=drivesdk"
        },
        "sheetName": {
          "__rl": true,
          "value": "gid=0",
          "mode": "list",
          "cachedResultName": "Sheet1",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1wMoRy4eHfBcIm_v3lQQ-H9oNTvAxP-fKRHomVerwkbc/edit#gid=0"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "Review_Date": "={{ $json.review_date }}",
            "Guest_Name": "={{ $json.guest_name }}",
            "Star_Rating": "={{ $json.star_rating }}",
            "Review_Text": "={{ $json.review_text }}",
            "Complaint_Category": "={{ $json.complaint_category }}",
            "Severity": "={{ $json.severity }}",
            "Emotional_Tone": "={{ $json.emotional_tone }}",
            "Specific_Issue": "={{ $json.specific_issue }}",
            "Key_Quote": "={{ $json.key_quote }}",
            "Review_URL": "={{ $json.review_url }}"
          },
          "matchingColumns": [],
          "schema": [
            {
              "id": "Review_Date",
              "displayName": "Review_Date",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "Guest_Name",
              "displayName": "Guest_Name",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "Star_Rating",
              "displayName": "Star_Rating",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "Review_Text",
              "displayName": "Review_Text",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "Complaint_Category",
              "displayName": "Complaint_Category",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "Severity",
              "displayName": "Severity",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "Emotional_Tone",
              "displayName": "Emotional_Tone",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "Specific_Issue",
              "displayName": "Specific_Issue",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "Key_Quote",
              "displayName": "Key_Quote",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "Review_URL",
              "displayName": "Review_URL",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.5,
      "position": [
        560,
        -80
      ],
      "id": "0a6eaf6b-1a5d-4428-9bfa-db0d8bdf6c89",
      "name": "Log to Google Sheet",
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "LOs2dbk9lby0NfDM",
          "name": "Google Sheets account"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const items = $('Edit Fields').all();\n\nif (items.length === 0) {\n  return [{\n    json: {\n      total_negative_reviews: 0,\n      category_breakdown: {},\n      severity_breakdown: {},\n      emotional_tone_breakdown: {},\n      top_issues: [],\n      hotel_name: 'Unknown'\n    }\n  }];\n}\n\nconst categoryCount = {};\nconst severityCount = {};\nconst emotionalToneCount = {};\nconst allIssues = [];\nconst hotel_name = items[0].json.hotel_name || 'Unknown';\n\nitems.forEach(item => {\n  const data = item.json;\n  \n  const category = data.complaint_category || 'Other';\n  categoryCount[category] = (categoryCount[category] || 0) + 1;\n  \n  const severity = data.severity || 'low';\n  severityCount[severity] = (severityCount[severity] || 0) + 1;\n  \n  const tone = data.emotional_tone || 'Calm';\n  emotionalToneCount[tone] = (emotionalToneCount[tone] || 0) + 1;\n  \n  allIssues.push({\n    issue: data.specific_issue || '',\n    quote: data.key_quote || '',\n    guest: data.guest_name || 'Anonymous',\n    date: data.review_date || '',\n    rating: data.star_rating || 0,\n    url: data.review_url || '',\n    severity: data.severity || 'low',\n    category: data.complaint_category || 'Other'\n  });\n});\n\nconst severityOrder = { critical: 4, high: 3, medium: 2, low: 1 };\nallIssues.sort((a, b) => {\n  return (severityOrder[b.severity] || 0) - (severityOrder[a.severity] || 0);\n});\n\nconst topIssues = allIssues.slice(0, 5);\n\nreturn [{\n  json: {\n    total_negative_reviews: items.length,\n    category_breakdown: categoryCount,\n    severity_breakdown: severityCount,\n    emotional_tone_breakdown: emotionalToneCount,\n    top_issues: topIssues,\n    hotel_name: hotel_name\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        752,
        -80
      ],
      "id": "ef6ee039-384d-48ee-b09e-022132dacbd6",
      "name": "Aggregate Summary"
    },
    {
      "parameters": {
        "sendTo": "hotelmanager@example.com",
        "subject": "=Weekly Guest Experience Report - {{ $json.hotel_name }}",
        "message": "=<html>\n<head>\n  <style>\n    body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; background: #f5f5f5; margin: 0; padding: 0; }\n    .container { max-width: 700px; margin: 20px auto; background: white; border-radius: 10px; overflow: hidden; box-shadow: 0 4px 20px rgba(0,0,0,0.15); }\n    .header { background: linear-gradient(135deg, #1e3a8a 0%, #1e40af 100%); color: white; padding: 30px; text-align: center; }\n    .header h1 { margin: 0 0 10px 0; font-size: 26px; }\n    .header .subtitle { font-size: 18px; opacity: 0.95; margin-top: 5px; }\n    .content { padding: 30px; }\n    .stats-section { margin: 25px 0; }\n    .stats-section h3 { color: #1e3a8a; border-bottom: 2px solid #1e3a8a; padding-bottom: 10px; margin-bottom: 15px; }\n    .stat-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 15px; margin: 15px 0; }\n    .stat-box { background: #f8f9fa; padding: 15px; border-radius: 8px; text-align: center; border: 1px solid #dee2e6; }\n    .stat-number { font-size: 28px; font-weight: bold; color: #dc2626; margin: 0; }\n    .stat-label { font-size: 13px; color: #666; margin-top: 5px; }\n    .breakdown-item { background: #f8f9fa; padding: 12px 15px; margin: 8px 0; border-radius: 5px; display: flex; justify-content: space-between; align-items: center; }\n    .breakdown-label { font-weight: 500; color: #333; }\n    .breakdown-count { background: #1e3a8a; color: white; padding: 4px 12px; border-radius: 15px; font-size: 14px; font-weight: bold; }\n    .issue-card { background: #fef3c7; padding: 15px; margin: 12px 0; border-radius: 8px; border-left: 4px solid #f59e0b; }\n    .issue-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; }\n    .issue-category { background: #1e3a8a; color: white; padding: 4px 10px; border-radius: 12px; font-size: 12px; font-weight: bold; }\n    .issue-severity { padding: 4px 10px; border-radius: 12px; font-size: 12px; font-weight: bold; }\n    .severity-critical { background: #dc2626; color: white; }\n    .severity-high { background: #f97316; color: white; }\n    .severity-medium { background: #facc15; color: #000; }\n    .severity-low { background: #4ade80; color: #000; }\n    .issue-text { color: #555; font-style: italic; margin: 8px 0; }\n    .issue-quote { background: white; padding: 10px; border-left: 3px solid #f59e0b; margin: 8px 0; font-size: 14px; color: #666; }\n    .issue-guest { font-size: 13px; color: #666; margin-top: 8px; }\n    .recommendations { background: #dbeafe; padding: 20px; margin: 25px 0; border-radius: 8px; border: 2px solid #1e3a8a; }\n    .recommendations h3 { color: #1e3a8a; margin-top: 0; }\n    .recommendations ul { margin: 10px 0; padding-left: 25px; line-height: 1.8; }\n    .footer { background: #f5f5f5; padding: 20px; text-align: center; color: #666; font-size: 12px; border-top: 1px solid #ddd; }\n  </style>\n</head>\n<body>\n  <div class=\"container\">\n    <div class=\"header\">\n      <h1>🏨 Weekly Guest Experience Report</h1>\n      <div class=\"subtitle\">{{ $json.hotel_name }}</div>\n    </div>\n    \n    <div class=\"content\">\n      <div class=\"stats-section\">\n        <h3>📊 Negative Reviews Overview</h3>\n        <div class=\"stat-grid\">\n          <div class=\"stat-box\">\n            <div class=\"stat-number\">{{ $json.total_negative_reviews }}</div>\n            <div class=\"stat-label\">Total Negative Reviews</div>\n          </div>\n          <div class=\"stat-box\">\n            <div class=\"stat-number\">{{ Object.keys($json.category_breakdown).length }}</div>\n            <div class=\"stat-label\">Issue Categories</div>\n          </div>\n        </div>\n      </div>\n      \n      <div class=\"stats-section\">\n        <h3>🗂️ Guest Complaint Categories</h3>\n        {{ Object.keys($json.category_breakdown).map(cat => `\n        <div class=\"breakdown-item\">\n          <span class=\"breakdown-label\">${cat}</span>\n          <span class=\"breakdown-count\">${$json.category_breakdown[cat]}</span>\n        </div>\n        `).join('') }}\n      </div>\n      \n      <div class=\"stats-section\">\n        <h3>⚠️ Severity Breakdown</h3>\n        {{ Object.keys($json.severity_breakdown).map(sev => `\n        <div class=\"breakdown-item\">\n          <span class=\"breakdown-label\">${sev.charAt(0).toUpperCase() + sev.slice(1)}</span>\n          <span class=\"breakdown-count\">${$json.severity_breakdown[sev]}</span>\n        </div>\n        `).join('') }}\n      </div>\n      \n      <div class=\"stats-section\">\n        <h3>😤 Guest Emotional Tone</h3>\n        {{ Object.keys($json.emotional_tone_breakdown).map(tone => `\n        <div class=\"breakdown-item\">\n          <span class=\"breakdown-label\">${tone}</span>\n          <span class=\"breakdown-count\">${$json.emotional_tone_breakdown[tone]}</span>\n        </div>\n        `).join('') }}\n      </div>\n      \n      <div class=\"stats-section\">\n        <h3>🔥 Top Priority Issues</h3>\n        {{ $json.top_issues.map(issue => `\n        <div class=\"issue-card\">\n          <div class=\"issue-header\">\n            <span class=\"issue-category\">${issue.category}</span>\n            <span class=\"issue-severity severity-${issue.severity}\">${issue.severity.toUpperCase()}</span>\n          </div>\n          <div class=\"issue-text\"><strong>Issue:</strong> ${issue.issue}</div>\n          <div class=\"issue-quote\">\"${issue.quote}\"</div>\n          <div class=\"issue-guest\">— ${issue.guest} | ⭐ ${issue.rating}/5 | ${issue.date}</div>\n          <a href=\"${issue.url}\" target=\"_blank\" style=\"color: #1e3a8a; font-size: 13px; text-decoration: none;\">→ View Full Review</a>\n        </div>\n        `).join('') }}\n      </div>\n      \n      <div class=\"recommendations\">\n        <h3>💡 Recommended Actions</h3>\n        <ul>\n          <li><strong>Immediate Response:</strong> Address all critical/high severity issues within 24 hours</li>\n          <li><strong>Housekeeping Training:</strong> If Room Cleanliness is top category, schedule deep-clean audits</li>\n          <li><strong>Maintenance Priority:</strong> Fix all reported equipment/facility issues this week</li>\n          <li><strong>Staff Coaching:</strong> Review Front Desk Service complaints with team</li>\n          <li><strong>Guest Outreach:</strong> Consider reaching out to highly dissatisfied guests for recovery</li>\n        </ul>\n      </div>\n    </div>\n    \n    <div class=\"footer\">\n      <p><strong>Automated Weekly Guest Experience Analysis</strong></p>\n      <p>Generated on {{ new Date().toLocaleDateString('en-US', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }) }}</p>\n      <p>This is an automated report. Please do not reply to this email.</p>\n    </div>\n  </div>\n</body>\n</html>",
        "options": {}
      },
      "type": "n8n-nodes-base.gmail",
      "typeVersion": 2.1,
      "position": [
        944,
        -80
      ],
      "id": "6745de63-fddb-4853-bf64-93438aa1eb0d",
      "name": "Send Weekly Summary Email",
      "webhookId": "88773611-a60f-4273-b3ca-2b2d7ba3f254",
      "credentials": {
        "gmailOAuth2": {
          "id": "cyqCGWcggZNMcSOv",
          "name": "Gmail account"
        }
      }
    }
  ],
  "pinData": {},
  "connections": {
    "Weekly Schedule - Monday 9 AM": {
      "main": [
        [
          {
            "node": "Scrape Hotel Reviews",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Scrape Hotel Reviews": {
      "main": [
        [
          {
            "node": "Get Dataset Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Dataset Items": {
      "main": [
        [
          {
            "node": "Filter 1-2 Star Reviews",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter 1-2 Star Reviews": {
      "main": [
        [
          {
            "node": "AI: Analyze Review",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI: Analyze Review": {
      "main": [
        [
          {
            "node": "Parse AI Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse AI Response": {
      "main": [
        [
          {
            "node": "Edit Fields",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Edit Fields": {
      "main": [
        [
          {
            "node": "Log to Google Sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log to Google Sheet": {
      "main": [
        [
          {
            "node": "Aggregate Summary",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Aggregate Summary": {
      "main": [
        [
          {
            "node": "Send Weekly Summary Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "61750d52-457e-4194-a559-c48be5088812",
  "meta": {
    "templateCredsSetupCompleted": true,
    "instanceId": "3a43da28588548e21903e71cf1dc3ddd65c24bf0c62e7e4b77542ffe87ad79c6"
  },
  "id": "QHppJBLCHD72F5j5",
  "tags": []
}